package com.scs.application.modules.base.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.scs.application.consts.GlobalConsts;
import com.scs.application.consts.SerialKeys;
import com.scs.application.core.exception.BusinessException;
import com.scs.application.core.query.QueryContext;
import com.scs.application.core.service.TreeServiceImpl;
import com.scs.application.core.utils.StringUtils;
import com.scs.application.modules.base.dto.CategoryFromMscmDTO;
import com.scs.application.modules.base.dto.CategoryToMscmDTO;
import com.scs.application.modules.base.entity.MatrCategory;
import com.scs.application.modules.base.mapper.MatrCategoryMapper;
import com.scs.application.modules.base.service.MatrCategoryService;
import com.scs.application.modules.base.util.CommonService;
import com.scs.application.modules.sys.model.RestResult;
import com.scs.application.modules.thirdparty.dto.MatrCategoryDTO;
import com.scs.application.modules.thirdparty.service.MscmService;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 */
@Slf4j
@Service
public class MatrCategoryServiceImpl extends TreeServiceImpl<MatrCategoryMapper, MatrCategory> implements MatrCategoryService {

    @Autowired
    private MscmService mscmService;

    @Override
    public boolean saveOrUpdate(MatrCategory entity) {
        if (entity.isNewRecord()) {
            entity.setCode(serialRuleAdapter.getSerialRuleService().generateCode(SerialKeys.BASE_MATR_CATEGORY_CODE));
        } else {
            //无节点不可以编辑
            if ("000000".equals(entity.getCode())) {
                BusinessException.throwValidFail("编码为000000的品类为内置数据，不可以编辑");
            }
        }
        if(StringUtils.isBlank(entity.getParentId()) || "0".equals(entity.getParentId())){
            entity.setParentCode("0");
        }else{
            MatrCategory matrCategory = this.baseMapper.selectById(entity.getParentId());
            entity.setParentCode(matrCategory.getCode());
        }
        boolean saveOrUpdate = super.saveOrUpdate(entity);
        updatenodeKeys(entity.getParentId());
        return saveOrUpdate;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public RestResult syncMatrCategoryFromHrp(List<MatrCategoryDTO> dtos) {
        int insertMatrCategorys = 0;
        List<MatrCategory> matrCategoryList = this.list(Wrappers.<MatrCategory>query().select("id,code,category_name,hrp_code"));
        Map<String, MatrCategory> matrCategoryMap = matrCategoryList.stream().collect(Collectors.toMap(o -> o.getHrpCode(), o -> o, (o1, o2) -> o1));
        log.info("加载到{}条耗材品类数据", matrCategoryMap.size());
        List<MatrCategory> updateMatrCategorys = Lists.newArrayListWithCapacity(dtos.size());
        for (MatrCategoryDTO dto : dtos) {
            MatrCategory mc = matrCategoryMap.get(dto.getCode());
            MatrCategory matrCategory = new MatrCategory();
            if (mc == null) {
                matrCategory.setCode(serialRuleAdapter.getSerialRuleService().generateCode(SerialKeys.BASE_MATR_CATEGORY_CODE));
                matrCategory.setCategoryName(dto.getCategoryName()).setHrpCode(dto.getCode());
                this.insertCascadeById(matrCategory);
                insertMatrCategorys++;
                matrCategoryMap.put(dto.getCode(), matrCategory);
            }
        }

        for (MatrCategoryDTO dto : dtos) {
            MatrCategory mc = matrCategoryMap.get(dto.getCode());
            MatrCategory matrCategory = new MatrCategory();
            if (mc != null) {
                if ("0".equals(dto.getParentCode())||StringUtils.isBlank(dto.getParentCode())) {
                    matrCategory.setParentCode("0");
                    matrCategory.setParentId("0");
                } else {
                    MatrCategory code = this.getOne(Wrappers.<MatrCategory>query().eq("hrp_code", dto.getParentCode()));
                    if (code == null) {
                        throw new BusinessException("该品类的父级code不存在", dto.getParentCode());
                    }
                    matrCategory.setParentCode(code.getCode()).setParentId(code.getId());
                }
                matrCategory.setCategoryName(dto.getCategoryName())
                        .setHrpCode(dto.getCode())
                        .setId(mc.getId());
                updateMatrCategorys.add(matrCategory);
            }
        }
        if (!updateMatrCategorys.isEmpty()) {
            this.updateBatchById(updateMatrCategorys);
        }
        this.updatenodeKeys("0");

        log.info("本次同步耗材品类{}个，新增{}个", dtos.size(), insertMatrCategorys);

        return RestResult.ok("同步成功，"+String.format("本次同步耗材品类%s个，新增%s个",dtos.size(), insertMatrCategorys));
    }

    @Override
    public Page pageWithCategory(QueryContext context) {
        return this.baseMapper.pageWithCategory(context.getPage(), context.getWrapper(), context.getParams());
    }

    @Override
    public RestResult syncCategoryFromMscm() {
        // 获取MSCM系统中分类数据
        List<CategoryFromMscmDTO> mscmCategory = mscmService.getMatrCategory();
        log.info("从MSCM系统中获取到{}个分类", mscmCategory.size());
        if (mscmCategory.isEmpty()) {
            return RestResult.ok("同步成功，"+String.format("从MSCM系统中获取到%s个分类",0));
        }
        Map<String, String> parentMscmCategory = mscmCategory
                .stream().collect(Collectors.toMap(o -> o.getId(), o -> o.getParentId()));
        int insertMatrCategorys = 0;
        List<MatrCategory> matrCategoryList = this.list(Wrappers.<MatrCategory>query());
        Map<String, MatrCategory> matrCategoryMap = matrCategoryList
                .stream().collect(Collectors.toMap(o -> o.getMscmCode(), o -> o, (o1, o2) -> o1));
        log.info("加载到{}条耗材品类数据", matrCategoryMap.size());
        List<MatrCategory> updateMatrCategorys = Lists.newArrayListWithCapacity(mscmCategory.size());
//        新增/更新分类
        for (CategoryFromMscmDTO dto : mscmCategory) {
            if ("C0101".equals(dto.getCode())) {
                logger.debug("C0101");
            }
            MatrCategory mc = matrCategoryMap.get(dto.getCode());
            MatrCategory matrCategory = new MatrCategory();
            if (dto.getId().equals(GlobalConsts.CATEGORY_TOP_NODE)) continue;
            if (mc == null) {
                matrCategory.setCode(serialRuleAdapter.getSerialRuleService().generateCode(SerialKeys.BASE_MATR_CATEGORY_CODE));
                matrCategory.setCategoryName(dto.getName()).setMscmCode(dto.getId());
                this.insertCascadeById(matrCategory);
                insertMatrCategorys++;
                matrCategoryMap.put(dto.getId(), matrCategory);
            }else {
                mc.setCategoryName(dto.getName());
                this.updateCascadeById(mc);
            }
        }
//       构建树级关系
        for (CategoryFromMscmDTO dto : mscmCategory) {
            MatrCategory mc = matrCategoryMap.get(dto.getId());
            MatrCategory mcParent = matrCategoryMap.get(dto.getParentId());
            if (dto.getId().equals(GlobalConsts.CATEGORY_TOP_NODE)) continue;
            if (mcParent==null){
                mc.setParentCode(GlobalConsts.CATEGORY_TOP_NODE).setParentId(GlobalConsts.CATEGORY_TOP_NODE);
            } else {
                mc.setParentCode(mcParent.getCode()).setParentId(mcParent.getId());
            }
            updateMatrCategorys.add(mc);
        }
        if (!updateMatrCategorys.isEmpty()) {
            this.updateBatchById(updateMatrCategorys);
        }
//       修复node_key
        this.updatenodeKeys("0");
        log.info("本次同步耗材品类{}个，新增{}个", mscmCategory.size(), insertMatrCategorys);

        return RestResult.ok("同步成功，"+String.format("本次同步耗材品类%s个，新增%s个",mscmCategory.size(), insertMatrCategorys));
    }

    public String categoryToMscm() {
        String infoRet = "";
        int sum = 0;
        String beginDate = null;
        try {
            List<CategoryToMscmDTO> categoryToMscmDTOS = baseMapper.getCategoryToMscm();
            if (categoryToMscmDTOS.isEmpty()) {
                log.info("本次推送耗材分类:{}个", sum);
                infoRet = "本次推送耗材分类:0个";
                return infoRet;
            }
            log.info("本次推送耗材分类:{}个", categoryToMscmDTOS.size());

            List<List<CategoryToMscmDTO>> pushListSplit = CollUtil.split(categoryToMscmDTOS, 100);
            for(List<CategoryToMscmDTO> split : pushListSplit) {
                categoryToMscmSplit(beginDate,split);
                sum+=split.size();
            }
            log.info("MatrCategoryServiceImpl.categoryToMscm.本次推送品类: {}个", sum);
        } catch (Exception e) {
            log.error("MatrCategoryServiceImpl.categoryToMscm",e);
            infoRet = "推送失败，原因：" + e.getMessage();
        }finally {
            //推送消息给运营管理员 和管理员
            CommonService.pushMessageRole("推送耗材结束【matrServiceImpl.matrToMscm】", "", "admin_yy,admin");
        }
        return infoRet;
    }

    public void categoryToMscmSplit(String beginDate, List<CategoryToMscmDTO> categoryToMscmDTOS) {
        List<CategoryToMscmDTO> toMscmDTOS = mscmService.categoryToMscm(beginDate, categoryToMscmDTOS);

        if (toMscmDTOS == null || toMscmDTOS.size() == 0
                || toMscmDTOS.size() != categoryToMscmDTOS.size()) {
            throw new BusinessException("推送耗材分类返回数据不正确，应返回：" + categoryToMscmDTOS.size() +
                    "条数据，现只返回"+ toMscmDTOS.size() + "条");
        }
        List<MatrCategory> categoryList = this.list();
        List<MatrCategory> updateMatrCategorys = Lists.newArrayListWithCapacity(categoryList.size());
        Map<String, MatrCategory> matrCategoryMap
                = categoryList.stream().collect(Collectors.toMap(o -> o.getId(), o -> o, (o1, o2) -> o1));
        for (CategoryToMscmDTO toMscmDTO : toMscmDTOS) {
            MatrCategory matrCategory = matrCategoryMap.get(toMscmDTO.getId());
            if (matrCategory!=null){
                matrCategory.setMscmCode(toMscmDTO.getMscmCode());
                updateMatrCategorys.add(matrCategory);
            }
        }
        if (!updateMatrCategorys.isEmpty()){
            this.updateBatchById(updateMatrCategorys);
        }
    }

    /**
     * 更新 nodeKey childCount
     *
     */
    public void updatenodeKeys(String parentId) {
        List<MatrCategory> matrCategoryList = this.baseMapper.selectList(Wrappers.<MatrCategory>query().eq("parent_id", parentId).ne("code","000000"));
        if (matrCategoryList == null) {
            return;
        }
        int sn = 0;
        for (MatrCategory m : matrCategoryList) {
            sn += 1;
            MatrCategory mc = new MatrCategory();
            if ("0".equals(m.getParentId())) {
                mc.setNodeKey(String.format("%03d", sn)).setId(m.getId());
            } else {
                MatrCategory matrCategory = this.baseMapper.selectById(m.getParentId());
                mc.setNodeKey(matrCategory.getNodeKey() + String.format("%03d", sn)).setId(m.getId());
            }
            // 更新父级 下级数量 字段
            int childCount = this.count(Wrappers.<MatrCategory>query().eq("parent_id", m.getId()));
            mc.setChildCount(childCount);
            this.updateById(mc);
            updatenodeKeys(m.getId());
        }
    }


    @Override
    public String repairData() {
        MatrCategory matrCategoryRoot = new MatrCategory();
        matrCategoryRoot.setId("0");
        matrCategoryRoot.setCode("000000");
        matrCategoryRoot.setCategoryName("根分类");
        matrCategoryRoot.setParentId("-1");
        matrCategoryRoot.setParentCode("0");
        matrCategoryRoot.setNodeKey("000");
        MatrCategory matrCategoryDb = this.getOne(Wrappers.<MatrCategory>query().eq("code",matrCategoryRoot.getCode()));
        String msg ="品类修复结束";
        if (matrCategoryDb == null) {
            this.save(matrCategoryRoot);
            msg+="，已增加跟分类";
        }else {//修复已存在的根分类
            this.update(
                    Wrappers.<MatrCategory>update()
                            .eq("code",matrCategoryRoot.getCode())
                            .set("id",matrCategoryRoot.getId())
                            .set("parent_id",matrCategoryRoot.getParentId())
                            .set("node_key",matrCategoryRoot.getNodeKey())
                            .set("category_name",matrCategoryRoot.getCategoryName())
            );
            msg+=String.format("，根分类 id已修复为%s，父id已修复为%s，节点key已修复为%s，名称已修复为%s",matrCategoryRoot.getId(),matrCategoryRoot.getParentId(),matrCategoryRoot.getNodeKey(),matrCategoryRoot.getCategoryName());
        }

        //修复根分类下级分类的父id
        int countChild = this.count(Wrappers.<MatrCategory>query().eq("parent_code", matrCategoryRoot.getCode()));
        if (countChild > 0) {
            this.update(Wrappers.<MatrCategory>update().eq("parent_code", matrCategoryRoot.getCode()).set("parent_id",matrCategoryRoot.getId()));
            msg+="，根分类的直接下级品类所属父id已修复";
        }

        this.updatenodeKeys("0");
        msg+="，nodekey修复结束";

        return msg;
    }



    // his同步完操作
    @Override
    public void afterSyncHis() {
        // 修复上级关系
        List<MatrCategory> matrCategoryList = this.list(Wrappers.<MatrCategory>query().isNotNull("hrp_code_parent"));
        if (!matrCategoryList.isEmpty()) {
            Map<String,MatrCategory> byHrpCode = this.list(Wrappers.<MatrCategory>query().isNotNull("hrp_code"))
                    .stream().collect(Collectors.toMap(item -> item.getHrpCode(), temp -> temp));
            List<MatrCategory> matrCategoryListUpdate = new ArrayList<>();
            for(MatrCategory matrCategory : matrCategoryList) {
                if (byHrpCode.containsKey(matrCategory.getHrpCodeParent())) {
                    matrCategory.setParentCode(byHrpCode.get(matrCategory.getHrpCodeParent()).getCode());
                    matrCategory.setParentId(byHrpCode.get(matrCategory.getHrpCodeParent()).getId());
                    matrCategoryListUpdate.add(matrCategory);
                }
            }

            if (matrCategoryListUpdate.size() > 0) {
                this.updateBatchById(matrCategoryListUpdate);
            }
        }
        this.updatenodeKeys("0");
    }
}
